import { FieldManager } from './components';
import * as util from './util';

function createFormField(h, field, comp) {
  if (null == comp.build) return comp.build;

  const data = {
    props: {
      field,
      value: getValue(field, this),
      placeholder: util.genPlaceholder(field)
    },
    on: {
      update: event => this.$emit('update', event)
    }
  };

  return h(comp.build, data);
}

function getValue(field, ctx) {
  return ctx.value[field.fieldName];
}

const FormBuilder = {
  name: 'mform-builder',
  props: {
    fields: {
      type: Array,
      default: () => []
    },
    value: {
      type: Object,
      default: () => ({})
    },
    mode: {
      type: String,
      default: ''
    },
    isEditState: {
      type: Boolean,
      default: false
    }
  },
  data() {
    return {
      /* 远程验证数据 */
      remoteValidateData: {
        // 字段
        field: null,
        // 方法
        validateFunc: null
      },
      validateMap: {}, // 所有注册的验证方法
      sectionState: {} // 分割线展开闭合
    };
  },
  methods: {
    /**
     * @description: 构建formItem
     * @param {*} field
     * @param {*} createElement
     */
    buildFormItem(field, createElement) {
      const fieldName = field.fieldName;
      if (this.$slots[fieldName]) {
        return this.$slots[fieldName];
      }

      if (this.$scopedSlots[fieldName]) {
        return this.$scopedSlots[fieldName]({
          field,
          value: getValue(field, this)
        });
      }

      const comp = FieldManager.findField(field.formType);
      if (comp == null) {
        console.warn(
          `[not implement]: ${field.displayName}(${field.fieldName}): ${field.formType}. `
        );
        return null;
      }

      const formField = createFormField.call(this, createElement, field, comp);
      if (comp.formType == 'separator' || null == formField) return formField;

      const formItemClass = [];
      if (field.formType == 'attachment')
        formItemClass.push('form-item-attachment');
      if (field.formType === 'info') {
        return formField;
      }
      // 不可修改状态
      if (field.disabled && this.isEditState) {
        return (
          <form-view
            fields={[field]}
            allFields={this.fields}
            value={{ attribute: this.value }}
          ></form-view>
        );
      }
      return (
        <form-item
          label={field.displayName}
          class={formItemClass}
          key={field.fieldName}
          findRootEl={this.findRootEl}
          validation
        >
          {formField}
        </form-item>
      );
    },
    /** 获取该dom元素 */
    findRootEl() {
      return this.$el;
    },
    /**
     * 检测所有字段的结果，都验证通过，返回true, 否则返回false
     */
    validate(isSample = true) {
      const promises = Object.keys(this.validateMap).map(key => {
        return this.validateMap[key](isSample);
      });
      return Promise.all(promises)
        .then(results => results.every(msg => !msg))
        .catch(err => console.error('validate error', err));
    },
    /** 注册待验证的组件 */
    addFieldHandler(event) {
      event.stopPropagation();

      const { fieldName, validate } = event.detail;
      if (
        event.detail &&
        event.detail.field &&
        event.detail.field.formType === 'info'
      ) {
        return;
      }
      this.validateMap[fieldName] = validate;
    },
    removeFieldHandler(event) {
      event.stopPropagation();

      const { fieldName } = event.detail;
      delete this.validateMap[fieldName];
    },
    outsideSetRemoteValidateData(data) {
      this.$set(this, 'remoteValidateData', data);
    },
    /**
     * @description: 获取表单分组
     * @param {*} fields
     */
    getGroupField(fields) {
      let groupField = [];
      let groupItem = {
        separator: '',
        children: []
      };

      fields
        // 隐藏无需显示的字段
        .filter(field => !util.isHiddenField(field, this.value, this.fields))
        // 为隐藏的字段不显示
        .filter(field => field.isHidden == undefined || field.isHidden !== 1)
        // 为不可见的字段不显示 false 不可见  true 可见
        .filter(field => field.isVisible == undefined || field.isVisible)
        // 子表单字段设置隐藏的不显示
        .filter(
          field => field.setting?.isShow == undefined || field.setting?.isShow
        )
        // 隐藏无内容的分割线
        .filter((field, index, arr) => {
          if (field.formType != 'separator') return true;

          let next = arr[index + 1];
          return null != next && next.formType != 'separator';
        })
        // 根据分割线分组
        .forEach((curr, idx, arr) => {
          let next = arr[idx + 1];

          if (curr.formType === 'separator') {
            groupItem.separator = curr;
          } else {
            // 最后一个或下一个是分隔符
            if (!next || (next && next.formType === 'separator')) {
              groupItem.children.push(curr);
              groupField.push(groupItem);
              groupItem = {
                separator: '',
                children: []
              };
            } else {
              groupItem.children.push(curr);
            }
          }
        });
      return groupField;
    },

    /**
     * @description: 构建分割线
     * @param {*} field
     */
    buildSeparator(field, id) {
      const { formType, displayName } = field;
      // 分割线
      if (formType === 'separator') {
        const cn = `iconfont icon-fdn-select ${!this.sectionState[id] &&
          'reversal'}`;
        return displayName ? (
          <h4 class="section-title">
            {displayName}
            <i class={cn} onClick={() => this.toggleDisplay(id)}></i>
          </h4>
        ) : null;
      }
    },
    /**
     * @description: 分割展开闭合
     * @param {*} id
     */

    toggleDisplay(id) {
      this.sectionState[id] = !this.sectionState[id];
    }
  },
  render(createElement) {
    // 表单分组
    const groups = this.getGroupField(this.fields);
    const formGroups = groups.map((field, index) => {
      let separator, children, groupId;
      if (field.separator) {
        //构建分割线
        groupId = field.separator ? field.separator.id : index;
        if (this.sectionState[groupId] === undefined) {
          this.$set(this.sectionState, groupId, true);
        }
        separator = this.buildSeparator(field.separator, groupId);
      }
      if (field.children) {
        //构建items
        children = field.children.map(c =>
          this.buildFormItem(c, createElement)
        );
      }
      return (
        <div class="form-wrap">
          {separator}
          <div
            class={`form-item-group ${
              !this.sectionState[groupId] && groupId
                ? 'hide-form-item-group'
                : ''
            }`}
          >
            {children}
          </div>
        </div>
      );
    });

    return (
      <div class="form-builder">
        {this.$slots.default}
        {formGroups}
      </div>
    );
  },
  mounted() {
    this.$el.addEventListener('form.add.field', this.addFieldHandler);
    this.$el.addEventListener('form.remove.field', this.removeFieldHandler);
  },
  destroyed() {
    this.$el.removeEventListener('form.add.field', this.addFieldHandler);
    this.$el.removeEventListener('form.remove.field', this.removeFieldHandler);
  }
};

export default FormBuilder;
